package controllers

import command.CommandExec
import dao._
import implicits.BlastTool
import implicits.Implicits._
import models.Tables._
import org.apache.commons.io.FileUtils
import org.joda.time.DateTime
import play.api.libs.json.Json
import play.api.mvc.{AbstractController, ControllerComponents}
import tool.Pojo.CommandData
import tool.{FormTool, Tool}
import utils.Utils

import java.io.File
import java.nio.file.Files
import javax.inject.Inject
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future

/**
 * Created by yz on 16/9/2021
 */
class BlastController @Inject()(cc: ControllerComponents)(
  implicit val userDao: UserDao,
  implicit val sampleDao: SampleDao,
  implicit val modeDao: ModeDao,
) extends AbstractController(cc) with BlastTool {

  def blastnBefore() = Action { implicit request =>
    Ok(views.html.user.blast.blastn())
  }

  def blastn = Action(parse.multipartFormData) { implicit request =>
    val userId = Tool.getUserId
    val data = FormTool.queryForm.bindFromRequest.get
    val tmpDir = Tool.createTempDirectory("tmpDir")
    val seqFile =Tool.getSeqFile(tmpDir)
    data.method match {
      case "text" =>
        data.queryText.toFile(seqFile)
      case "file" =>
        val file = request.body.file("file").get
        file.ref.moveTo(seqFile, replace = true)
    }
    val outXmlFile = new File(tmpDir, "data.xml")
    val outHtmlFile = Tool.getOutHtmlFile(tmpDir)
    val outTableFile = Tool.getOutTableFile(tmpDir)
    val faFile = Tool.getSampleFileById(data.db.toInt)

    val command =
      s"""
         | ${Tool.blastFile.unixPath} -query ${seqFile.unixPath}  -db ${faFile.unixPath}  -outfmt 5 -evalue  ${data.evalue}  -max_target_seqs  ${data.maxTargetSeqs} -word_size ${data.wordSize}  -out  ${outXmlFile.unixPath}
         | python   ${Tool.blast2HtmlFile.unixPath}  -i  ${outXmlFile.unixPath} -o  ${outHtmlFile.unixPath} --template ${Tool.jinjaDir.unixPath}/blastn.jinja
         |perl ${Tool.binPath.unixPath}/Blast2table -format 10 -xml ${outXmlFile.unixPath} -header -top >${outTableFile.unixPath}
         |""".stripMargin
    val execCommand = CommandExec().exec { b =>
      CommandData(tmpDir, List(command))
    }

    if (execCommand.isSuccess) {
      Ok(Json.obj("valid" -> true, "path" -> tmpDir.getAbsolutePath.replaceAll("\\\\", "/"),
        "tableData" -> outTableFile.str))
    } else {
      Tool.deleteDirectory(tmpDir)
      Ok(Json.obj("valid" -> false, "message" -> execCommand.errorInfo))
    }
  }

  def blastResultBefore = Action {
    implicit request =>
      val data = FormTool.pathForm.bindFromRequest().get
      val id = FormTool.idForm.bindFromRequest().get.id
      Ok(views.html.user.blast.blastResult(data.path, id))
  }

  def blastResult = Action { implicit request =>
    val data = FormTool.pathForm.bindFromRequest().get
    val tmpDir = new File(data.path)
    val htmlFile = Tool.getOutHtmlFile(tmpDir)
    val block = tmpDir.getSyntenyData
    val json = Json.obj("html" -> s"${htmlFile.str}\n${Tool.scriptHtml}", "block" -> block)
    Tool.deleteDirectory(tmpDir)
    Ok(json)
  }

  def downloadByName = Action { implicit request =>
    val data = FormTool.nameForm.bindFromRequest().get
    val id = FormTool.idForm.bindFromRequest().get.id
    val faFile = Tool.getSampleFileById(id)
    val tmpDir = Tool.createTempDirectory("tmpDir")
    val seqFile = Tool.getSeqFile(tmpDir)
    val command =
      s"""
         |samtools faidx  ${faFile.unixPath} ${data.name}  >${seqFile.unixPath}
         |""".stripMargin
    val execCommand = CommandExec().exec { b =>
      CommandData(tmpDir, List(command))
    }
    if (execCommand.isSuccess) {
      Ok.sendFile(seqFile, onClose = () => {
        tmpDir.deleteQuietly
      }).withHeaders(
        CACHE_CONTROL -> "max-age=3600",
        CONTENT_DISPOSITION -> s"attachment; filename=${data.name}_complete.fasta",
        CONTENT_TYPE -> "application/x-download"
      )
    } else {
      NotFound
    }
  }

  def downloadByRange = Action { implicit request =>
    val data = FormTool.nameForm.bindFromRequest().get
    val id = FormTool.idForm.bindFromRequest().get.id
    val range = FormTool.rangeForm.bindFromRequest().get.range
    val faFile = Tool.getSampleFileById(id)
    val tmpDir = Tool.createTempDirectory("tmpDir")
    val seqFile =Tool.getSeqFile(tmpDir)
    val rangeStr = range.replaceAll("^.*:", "").trim.mySplit("to").map(_.trim).
      sortBy(_.toInt).mkString("-")
    val rangeInfo = s"${data.name}:${rangeStr}"
    val command =
      s"""
         |samtools faidx  ${faFile.unixPath} ${rangeInfo}  >${seqFile.unixPath}
         |""".stripMargin
    val execCommand = CommandExec().exec { b =>
      CommandData(tmpDir, List(command))
    }
    if (execCommand.isSuccess) {
      Ok.sendFile(seqFile, onClose = () => {
        tmpDir.deleteQuietly
      }).withHeaders(
        CACHE_CONTROL -> "max-age=3600",
        CONTENT_DISPOSITION -> s"attachment; filename=${data.name}_aligned.fasta",
        CONTENT_TYPE -> "application/x-download"
      )
    } else {
      NotFound
    }
  }

}
